package data.partition;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProcessData {

	public static String folder = "/home/quyet/experiments/partition/dblp64/1600";
	public static String fileName = "640000.txt";
	public static int total = 3200000;

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {

		// CheckData(folder+"/"+fileName);
		// folder = args[0];
		// String isRunPartition = args[1];
		// String part = args[2];
		// int p = Integer.parseInt(part);

		String isRunPartition = "1";
		int p = 64;

//		folder = args[0];
//		fileName = args[1];
//		total = Integer.parseInt(args[2]);

//		long startTime = System.currentTimeMillis();
//
//		if (isRunPartition.equals("1"))
//			GetData(folder + "/" + fileName);
//		else if (isRunPartition.equals("2"))
//			GraphPartition(p, folder + "/edges.txt.result_1_of_1");
//
//		long stopTime = System.currentTimeMillis();
//		long elapsedTime = stopTime - startTime;
//		System.out.println("\nFinished after: " + elapsedTime + " ms");

		SplitPartitions(64, folder+"/edges.txt.result_1_of_1");
		//CreatePartitions(32, 2938769);
		System.out.println("Finished");
	}

	public static final ArrayList<String> crosslinks = new ArrayList<String>();

	public static void GatherPartition(int key,
			HashMap<Integer, ArrayList<Integer>> listP,
			ArrayList<Node> listNodes, ArrayList<Integer> listIds)
			throws IOException {

		FileWriter fwPart = new FileWriter(folder + "/partition" + key + ".txt");
		BufferedWriter bwPart = new BufferedWriter(fwPart);
		String node = "";

		ArrayList<String> listOutNodes = new ArrayList<String>();
		ArrayList<Integer> listV = listP.get(key);

		ArrayList<Integer> listCheckOut = new ArrayList<Integer>();
		int countInput = 0;

		for (Integer v : listV) {
			node = "";
			int idx = listIds.indexOf(v);

			if (idx >= 0) {

				// check v is in-node?
				boolean check = false;
				for (Integer t : listP.keySet()) {
					if (t != key) {
						ArrayList<Integer> listN = listP.get(t);
						for (int n : listN) {
							int index = listIds.indexOf(n);
							if (index >= 0) {
								Node nt = listNodes.get(index);
								if (nt.neighbors.contains(v)) {
									check = true;
								}
							}
							if (check)
								break;
						}
					}
					if (check)
						break;
				}
				// end check v in in-node

				// set in - out node
				Node vi = listNodes.get(idx);
				node = vi.id + ":";
				if (check) {
					countInput += 1;
					node += "1\t";
				} else
					node += "0\t";

				node += vi.label;

				for (int s : vi.neighbors) {

					if (!listCheckOut.contains(s)) {
						if (!listV.contains(s)) {
							int index = listIds.indexOf(s);
							if (index >= 0) {
								Node a = listNodes.get(index);
								listOutNodes.add(s + ":2\t" + a.label);
							} else {
								listOutNodes.add(s + ":2");
							}
						}
						listCheckOut.add(s);
					}
					node += "\t" + s;
				}

			} else {
				node = v + ":0";
			}

			bwPart.write(node + "\n");
		}

		for (String outnode : listOutNodes)
			bwPart.write(outnode + "\n");

		bwPart.close();

		crosslinks.add(countInput + "\t" + listCheckOut.size() + "\t"
				+ listV.size());

	}

	public static void GraphPartition(int partitions, String filePartition) {
		try {

			final HashMap<Integer, ArrayList<Integer>> listP = new HashMap<Integer, ArrayList<Integer>>();
			ArrayList<ArrayList<Integer>> tmp = new ArrayList<ArrayList<Integer>>(
					partitions);

			String strLine = null;

			FileReader frPart = new FileReader(new File(filePartition));
			BufferedReader brPart = new BufferedReader(frPart);

			for (int i = 0; i < partitions; i++) {
				tmp.add(new ArrayList<Integer>());
			}

			int p = 0; // partition
			while ((strLine = brPart.readLine()) != null) {
				String[] row = strLine.split("\t");
				p = Integer.parseInt(row[1]) - 1;
				tmp.get(p).add(Integer.parseInt(row[0]));
			}
			for (int i = 0; i < partitions; i++) {
				listP.put(i + 1, tmp.get(i));
			}

			brPart.close();

			// Load primitive data

			FileReader fNode = new FileReader(new File(folder + "/nodes.txt"));
			BufferedReader bNode = new BufferedReader(fNode);
			strLine = null;

			final ArrayList<Node> listNodes = new ArrayList<Node>();
			final ArrayList<Integer> listIds = new ArrayList<Integer>();

			while ((strLine = bNode.readLine()) != null) {
				String[] row = strLine.split("\t");

				ArrayList<Integer> neighbors = new ArrayList<Integer>();
				String attributes = "";
				for (int i = 1; i < 9; i++)
					attributes += row[i] + "\t";

				if (attributes.length() > 0)
					attributes = attributes.substring(0,
							attributes.length() - 1);

				for (int i = 9; i < row.length; i++)
					neighbors.add(Integer.parseInt(row[i]));

				listNodes.add(new Node(Integer.parseInt(row[0]), attributes,
						neighbors));
				listIds.add(Integer.parseInt(row[0]));
			}
			bNode.close();

			int nrOfProcessors = Runtime.getRuntime().availableProcessors();
			if (nrOfProcessors >= 2)
				nrOfProcessors -= 1;
			if (nrOfProcessors > 64)
				nrOfProcessors = 64;

			System.out.println("Using " + nrOfProcessors + " processors");

			ExecutorService eservice = Executors
					.newFixedThreadPool(nrOfProcessors);

			for (Integer k : listP.keySet()) {
				final int key = k;
				eservice.submit(new Runnable() {
					@Override
					public void run() {
						try {
							GatherPartition(key, listP, listNodes, listIds);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				});
			}

			eservice.shutdown();
			while(!eservice.isTerminated()){			
			}

			FileWriter fCross = new FileWriter(new File(folder
					+ "/crosslinks.txt"));
			BufferedWriter bCross = new BufferedWriter(fCross);
			for (String s : crosslinks)
				bCross.write(s + "\n");
			bCross.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void GetData(String filepath) {
		// TODO Auto-generated method stub

		try {
			FileReader fr = new FileReader(new File(filepath));
			BufferedReader br = new BufferedReader(fr);

			FileWriter fNode = new FileWriter(folder + "/nodes.txt");
			FileWriter fEdge = new FileWriter(folder + "/edges.txt");
			FileWriter fLabel = new FileWriter(folder + "/labels.txt");
			FileWriter fInfo = new FileWriter(folder + "/info.txt");
			BufferedWriter bwNode = new BufferedWriter(fNode);
			BufferedWriter bwEdge = new BufferedWriter(fEdge);
			BufferedWriter bwLalel = new BufferedWriter(fLabel);
			BufferedWriter bwInfo = new BufferedWriter(fInfo);

			ArrayList<String> listL = new ArrayList<String>();

			String strLine;
			HashMap<String, Node> V = new HashMap<String, Node>();
			int id = 1;
			int countEdges = 0;
			int line = 0;

			while ((strLine = br.readLine()) != null) {

				String[] row = strLine.split("\t");
				if (row.length >= 9) {

					 if (!listL.contains(row[3])) {
						 listL.add(row[3]);
						 bwLalel.write(row[3] + "\n");
					 }

					Node ni = new Node(id, row[0]);
					Node tmp = V.get(row[0]);
					if (tmp == null) {
						V.put(row[0], ni);
						id += 1;
					} else {
						ni = tmp;
					}
					String node = ni.id + "";

					for (int i = 1; i < 9; i++)
						node += "\t" + row[i];

					for (int i = 9; i < row.length; i++) {
						// Node nj = new Node(row[i]);
						Node m = V.get(row[i]);
						if (m == null) {
							V.put(row[i], new Node(id, row[i]));
							bwEdge.write(ni.id + "\t" + id + "\n");
							node += "\t" + id;
							id++;
						} else {
							bwEdge.write(ni.id + "\t" + m.id + "\n");
							node += "\t" + m.id;
						}
						countEdges += 1;
					}
					bwNode.write(node);
					bwNode.newLine();
				}
				line += 1;
				System.out.println("Running " + (V.size()+countEdges) + "/" + total + " -> "
						+ (100 * (V.size()+countEdges) / total) + "% -> line: "+line);
				if(V.size()+countEdges>=total)
					break;
			}

			bwInfo.write(V.size() + "\t" + countEdges + "\t"
					+ (V.size() + countEdges) +"\n");
			bwInfo.write("number of lables: "+listL.size() +"\n");			
			bwInfo.write("line: "+line+" in file "+filepath);
			br.close();
			bwInfo.close();
			bwLalel.close();
			bwNode.close();
			bwEdge.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void CheckData(String fileNode) throws IOException {

		FileReader fNode = new FileReader(new File(folder + "/nodes.txt"));
		BufferedReader bNode = new BufferedReader(fNode);
		String strLine = null;

		ArrayList<Node> listNodes = new ArrayList<Node>();
		ArrayList<Integer> listIds = new ArrayList<Integer>();

		while ((strLine = bNode.readLine()) != null) {
			String[] row = strLine.split("\t");

			ArrayList<Integer> neighbors = new ArrayList<Integer>();
			for (int i = 9; i < row.length; i++)
				neighbors.add(Integer.parseInt(row[i]));

			listNodes.add(new Node(Integer.parseInt(row[0]), neighbors));
			listIds.add(Integer.parseInt(row[0]));
		}
		bNode.close();

		int count = 0;
		for (Node n : listNodes) {
			for (int e : n.neighbors)
				if (!listIds.contains(e)) {
					System.out.println(n.id + ": " + e);
					count += 1;
				}
		}

		System.out.println("Sum : " + count);
	}

	public static void CreatePartitions(int partitions, int nodes)
			throws IOException {
		int total = nodes / partitions;
		int mod = nodes % partitions;
		int add = 0;
		for (int i = 1; i <= partitions; i++) {
			FileWriter file = new FileWriter(folder + "/parts/part" + i);
			BufferedWriter bw = new BufferedWriter(file);
			int k = 0;
			for (k = total * (i - 1) + add; k < total * i + add; k++) {
				bw.write((k + 1) + "\n");
			}
			if (add < mod) {
				bw.write((k + 1) + "\n");
				add += 1;
			}
			bw.close();
		}
	}

	public static void SplitPartitions(int partitions, String filePart)
			throws IOException {
		HashMap<Integer, ArrayList<Integer>> listP = new HashMap<Integer, ArrayList<Integer>>();
		ArrayList<ArrayList<Integer>> tmp = new ArrayList<ArrayList<Integer>>(
				partitions);

		String strLine = null;

		FileReader frPart = new FileReader(new File(filePart));
		BufferedReader brPart = new BufferedReader(frPart);

		for (int i = 0; i < partitions; i++) {
			tmp.add(new ArrayList<Integer>());
		}

		int p = 0; // partition
		while ((strLine = brPart.readLine()) != null) {
			String[] row = strLine.split("\t");
			p = Integer.parseInt(row[1]) - 1;
			tmp.get(p).add(Integer.parseInt(row[0]));
		}
		for (int i = 0; i < partitions; i++) {
			listP.put(i + 1, tmp.get(i));
		}
		brPart.close();

		for (Entry<Integer, ArrayList<Integer>> part : listP.entrySet()) {
			int k = part.getKey();
			ArrayList<Integer> items = part.getValue();
			FileWriter fP = new FileWriter(folder + "/parts/part" + k);
			BufferedWriter bwNode = new BufferedWriter(fP);
			for (int i : items)
				bwNode.write(i + "\n");
			bwNode.close();
		}
	}

}

// Vertex define
class Node {
	int id;
	String name;
	String label;
	ArrayList<Integer> neighbors;

	public Node() {
		this.name = "";
		this.label = "";
	}

	public Node(String name) {
		this.name = name;
	}

	public Node(Integer id, String name) {
		this.id = id;
		this.name = name;
	}

	public Node(Integer id, ArrayList<Integer> neighbors) {
		this.id = id;
		this.neighbors = neighbors;
	}

	public Node(Integer id, String label, ArrayList<Integer> neighbors) {
		this.id = id;
		this.label = label;
		this.neighbors = neighbors;
	}

	public Node(Integer id, String name, String label) {
		this.id = id;
		this.name = name;
		this.label = label;
	}

	@Override
	public boolean equals(Object obj) {
		boolean check = false;
		if (obj == null)
			return false;
		else if (obj == this)
			return true;
		else {
			if (obj instanceof Node && obj.getClass() == this.getClass()) {
				final Node t = (Node) obj;
				check = this.name.equals(t.name);
			}
		}
		return check;
	}

	@Override
	public int hashCode() {
		int hash = 7;
		hash = (37 * hash) + (null == this.name ? 0 : this.name.hashCode());
		return hash;
	}
}
